'''
programme: ftpController.py
usage: python ftpController.py [20130520]
author: lifengya@kingsoft.com
create on 2013.5.17
'''

import os
import sys
import time
import re
import ConfigParser
import ftpCoordination

#import path
workdir = os.path.dirname(os.path.realpath(__file__))
libpath = os.path.join(workdir,'..','lib')
print libpath
sys.path.append(libpath)

from mylib import log
from myftplib import MyFTP

class controller():
	def __init__(self,configfile):
		'''
		self.starttime = time.time()
		self.autoQuittime = self.starttime + 3600 * 24 + 3600 * 24
		self.date = date
		self.alllist = self.getlist()
		self.childProcessNum = 0
		#the maxmum of running process
		self.maxChildNum = 10
		#sleep time(seconds) before refreshing
		self.sleeptime = 30
		'''
		self.childProcessNum = 0
		#the maxmum of running process
		self.maxChildNum = 5
		self.config = configfile
		self.getconfig()
		
	def getconfig(self):
		parser = ConfigParser.ConfigParser()
		#ftp config
		parser.read(self.config)
		self.ftpHost = parser.get('ftp_con','host')
		self.ftpPort = parser.get('ftp_con','port')
		self.ftpUsername = parser.get('ftp_con','username')
		self.ftpPassword = parser.get('ftp_con','password')
		self.passive_mode = parser.get('ftp_con','passive_mode')
		self.remotefilePattern = parser.get('remote_file','remote_file_pattern')
		self.localTemppath = parser.get('local_path','localTemppath')
		self.localTargetpath = parser.get('local_path','localTargetpath')

		#database config
		db = {}
		db['database'] = parser.get('ftp_record_database','database')
		db['host'] = parser.get('ftp_record_database','host')
		db['user'] = parser.get('ftp_record_database','username')
		db['password'] = parser.get('ftp_record_database','password')
		db['table'] = parser.get('ftp_record_database','tablename')
		self.type = parser.get('ftp_record_database','type')
		self.db = db
		#self.coord = ftpCoordination.ftpCoord(fileData,remotefile,localfile)

		#config check
		assert self.ftpHost and self.ftpUsername and self.ftpPassword and self.remotefilePattern and self.localTemppath and self.localTargetpath and self.type and self.db , "sth. missed in config file: %s" % (self.config)

	def connectftp(self):
		#connect ot ftp
		try:
			myftp = MyFTP()
			myftp.connect(self.ftpHost,self.ftpPort)
			myftp.login(self.ftpUsername,self.ftpPassword)
			#myftp.set_pasv(True)
			if self.passive_mode == '0':
				myftp.set_pasv(False)
			elif self.passive_mode == '1':
				myftp.set_pasv(True)
			else:
				raise Exception("passive mode wrong configuration!")
		except Exception,error:
			log("can't login to ftp server: %s" % (error))
			sys.exit()
		return myftp

	def download(self,remotefile):
		ftpConn = self.connectftp()
		#get remote file size
		Remfilesize = ftpConn.size(remotefile)
		#get local fullname
		localfile = os.path.join(self.localTemppath,remotefile)
		#add 'lock' on this job
		coord = ftpCoordination.ftpCoord(self.db,self.type)
		coord.setname(remotefile,localfile)
		coord.cleanlocks()
		if not coord.lock():
			sys.exit()
		ftpSuccess = 0
		for i in range(1,4):
			if os.path.isfile(localfile):
			    rest=os.stat(localfile).st_size
			    if rest:
			        if rest != Remfilesize:
			    		ftpConn.retrbinary('RETR ' + remotefile,open(localfile,'ab').write,Remfilesize,rest)
			else:
			    ftpConn.retrbinary('RETR ' + remotefile,open(localfile,'wb').write,Remfilesize)
	
			Locfilestat = os.stat(localfile)
			Locfilesize = Locfilestat.st_size
			
			#check if works done correctly
			if Remfilesize == Locfilesize:
				#well done: print and update status to 1
				log("COPY %s TO %s ," % (remotefile,localfile) + "SIZE: %s" % (Remfilesize))
				ftpSuccess = 1
				break
			else:	
				log("Different sizes,sleep 120 seconds and try again..")
				time.sleep(120)
		if ftpSuccess == 0:
			coord.badjob()
		else:
			coord.goodjob()
		del coord

	def move(self,file):
		tempFullpath = os.path.join(self.localTemppath,file)
		targetFullpath = os.path.join(self.localTargetpath,file)
		mvCommand = "mv %s %s " % (tempFullpath,targetFullpath)
		log("Execute:%s" % (mvCommand))
		os.system(mvCommand)

	'''
	[single process mode]
	def main(self):
		log("Try to get a ftp list..")
		list = self.getlist()
		print "list:" ,list
		for file in list:
			#download this file
			log("Now downloading file: %s" % (file))
			self.download(file)
		log("Programme finished,transferd files: [%s]" % ",".join(list))
	'''

	'''
	[multiple process mode]
	'''
	def main(self):
		log("Try to get a ftp list..")
		list = self.getlist()
		for file in list:
			#log("Now downloading file: %s" % (file))
			pid = os.fork()
			if pid == 0:
				#child process,download this file
				self.download(file)
				self.move(file)
				sys.exit()
			else:
				#father process
				log("[child-pid]:%s [file]:%s" % (pid,file))
				pass
		log("Father process exit,make transferring files: [%s]" % ",".join(list))

	def getlist(self):
		ftpConn = self.connectftp()
		ftplist = ftpConn.nlst()
		ftplist.sort
		if ftplist:
			del ftplist[-1]
		coord = ftpCoordination.ftpCoord(self.db,self.type)
		runningProcess = int(coord.detectRunning())
		newList = []
		for file in ftplist:
			if runningProcess >= 3:
				break
			if not re.match(self.remotefilePattern,file):
				continue
			if coord.detectrecord(file):
				continue
			else:
				newList.append(file)
				runningProcess += 1
		del coord
		return newList
			
		
	def checkQuittime(self):
		now = time.time()
		if now >= self.autoQuittime:
			log("over time,now exit!")
			sys.exit()
#check arguments
argv = sys.argv
argvNum = len(argv)
if argvNum != 2:
	raise Exception ('Call me like this: python controller.py act_log.conf')

#get config
configfilename = argv[1]
currentpath = os.path.dirname(os.path.realpath(__file__))
configfullname = os.path.join(currentpath,'..','conf',configfilename)
if not os.path.exists(configfullname):
	raise Exception ('config file not found:%s' % (configfullname))

mycontroller = controller(configfullname)
mycontroller.main()

		
